package cn.taketoday.live.handler;

import com.alibaba.fastjson.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.buf.HexUtils;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Vector;

import cn.taketoday.live.component.ThreadComponent;
import cn.taketoday.live.config.GlobalData;
import cn.taketoday.live.config.settings.ThankGiftRuleSet;
import cn.taketoday.live.config.settings.ThankGiftSetConf;
import cn.taketoday.live.controller.DanmuWebsocket;
import cn.taketoday.live.data.BarrageHeader;
import cn.taketoday.live.data.Gift;
import cn.taketoday.live.data.enums.ShieldMessage;
import cn.taketoday.live.service.SettingsService;
import cn.taketoday.live.tools.CurrencyTools;
import cn.taketoday.live.utils.ByteUtils;
import cn.taketoday.live.utils.SpringUtils;
import cn.taketoday.live.utils.StructRuntimeException;
import lombok.extern.slf4j.Slf4j;
import struct.JavaStruct;
import struct.StructException;

/**
 * @author TODAY
 */
@Slf4j
public class MessageHandler {
  private boolean enable;
  private Map<ShieldMessage, Boolean> messageControlMap;
  private final DanmuWebsocket danmuWebsocket = SpringUtils.getBean(DanmuWebsocket.class);
  private final SettingsService settingsService = SpringUtils.getBean(SettingsService.class);
  private final ThreadComponent threadComponent = SpringUtils.getBean(ThreadComponent.class);
  private ThankGiftSetConf thankGiftSetConf;
  private HashSet<ThankGiftRuleSet> thankGiftRuleSets;

  public void setThankGiftSetConf(ThankGiftSetConf thankGiftSetConf) {
    this.thankGiftSetConf = thankGiftSetConf;
  }

  private static final Map<String, CommandHandler> commandHandlers = new HashMap<>();

  private static final MessageHandler instance = new MessageHandler();

  public static MessageHandler getInstance() {
    return instance;
  }

  private MessageHandler() { }

  static {
    commandHandlers.put("DANMU_MSG", new BarrageCommandHandler());
    commandHandlers.put("SEND_GIFT", new GiftCommandHandler());
    commandHandlers.put("WELCOME", new WelcomeCommandHandler());
    commandHandlers.put("LIVE", new LiveEnableCommandHandler());
    commandHandlers.put("GUARD_BUY", new GuardBuyCommandHandler());
    commandHandlers.put("WELCOME_GUARD", new WelcomeGuardCommandHandler());
    commandHandlers.put("ANCHOR_LOT_START", new AnchorLotStartCommandHandler());
    commandHandlers.put("ROOM_BLOCK_MSG", new RoomBlockMessageCommandHandler());
    commandHandlers.put("SUPER_CHAT_MESSAGE", new SuperChatMessageCommandHandler());
    commandHandlers.put("INTERACT_WORD", new InteractWordCommandHandler());
    commandHandlers.put("ROOM_REAL_TIME_MESSAGE_UPDATE", (context -> {
      final JSONObject jsonObject = context.getOriginal();
      // fans = JSONObject.parseObject(jsonObject.getString("data"), Fans.class);
      // stringBuilder.append(JodaTimeUtils.getCurrentTimeString()).append(":消息推送:").append("房间号")
      // .append(fans.getRoomid()).append("的粉丝数:").append(fans.getFans());
      GlobalData.FAN_SNUM = JSONObject.parseObject(jsonObject.getString("data")).getLong("fans");
    }));
    commandHandlers.put("PREPARING", (context -> {
      // 直播准备中(或者是关闭直播)
      GlobalData.lIVE_STATUS = 0;
      final SettingsService settingsService = context.getMessageHandler().getSettingsService();
      settingsService.updateSettings(GlobalData.centerSetConf);
      GlobalData.IS_ROOM_POPULARITY = false;
//					LOGGER.debug("直播准备中(或者是关闭直播):::" + message);
    }));
  }

  private JSONObject getJsonObject(String message) {
    try {
      return JSONObject.parseObject(message);
    }
    catch (Exception e) {
      log.debug("抛出解析异常:", e);
      return null;
    }
  }

  public void handle(String message) {
    if (!StringUtils.isEmpty(message)) {
      JSONObject jsonObject = getJsonObject(message);
      if (jsonObject != null) {
        String cmd = jsonObject.getString("cmd");
        final CommandHandler commandHandler = commandHandlers.get(cmd);
        if (commandHandler != null) {
          final CommandContext commandContext = new CommandContext(jsonObject, this);
          try {
            commandHandler.handle(commandContext);
          }
          catch (Exception e) {
            log.error("CommandHandler: {} 发生异常", commandHandler, e);
          }
        }
        else {
          System.out.println(jsonObject);
        }
      }
    }
  }

  //获取发送礼物code
  public String sendCode() {
    String code = "";
    synchronized(GlobalData.centerSetConf) {
      code = CurrencyTools.sendGiftCode();
      settingsService.update(GlobalData.centerSetConf);
    }
    return code;
  }

  public void delayGiftTimeSetting() {
    synchronized(GlobalData.parsethankGiftThread) {
      if (GlobalData.parsethankGiftThread != null) {
        threadComponent.startParseThankGiftThread(getThankGiftSetConf(), getThankGiftRuleSets());
      }
    }
  }

  public ThankGiftSetConf getThankGiftSetConf() {
    return thankGiftSetConf;
  }

  public synchronized void parseGiftSetting(Gift gift) {
    Vector<Gift> gifts = null;
    if (gift != null && !StringUtils.isEmpty(GlobalData.USERCOOKIE)) {

      if (GlobalData.parsethankGiftThread != null) {
        if (!GlobalData.parsethankGiftThread.TFLAG) {
          if (GlobalData.thankGiftConcurrentHashMap.size() > 0) {
            gifts = GlobalData.thankGiftConcurrentHashMap.get(gift.getUname());
            if (gifts != null) {
              int flagNum = 0;
              for (Gift giftChild : gifts) {
                int num1 = giftChild.getNum();
                int num2 = gift.getNum();
                long total_coin1 = giftChild.getTotal_coin();
                long total_coin2 = gift.getTotal_coin();
                if (giftChild.getGiftName().equals(gift.getGiftName())) {
                  giftChild.setNum(num1 + num2);
                  giftChild.setTotal_coin(total_coin1 + total_coin2);
                  delayGiftTimeSetting();
                  flagNum++;
                }
              }
              if (flagNum == 0) {
                gifts.add(gift);
                delayGiftTimeSetting();
              }
            }
            else {
              gifts = new Vector<>();
              gifts.add(gift);
              GlobalData.thankGiftConcurrentHashMap.put(gift.getUname(), gifts);
              delayGiftTimeSetting();
            }
          }
          else {
            gifts = new Vector<>();
            gifts.add(gift);
            GlobalData.thankGiftConcurrentHashMap.put(gift.getUname(), gifts);
            delayGiftTimeSetting();
          }
        }
      }
    }
  }

  public Map<ShieldMessage, Boolean> getMessageControlMap() {
    return messageControlMap;
  }

  public void setMessageControlMap(Map<ShieldMessage, Boolean> messageControlMap) {
    this.messageControlMap = messageControlMap;
  }

  public HashSet<ThankGiftRuleSet> getThankGiftRuleSets() {
    return thankGiftRuleSets;
  }

  public void setThankGiftRuleSets(HashSet<ThankGiftRuleSet> thankGiftRuleSets) {
    this.thankGiftRuleSets = thankGiftRuleSets;
  }

  public DanmuWebsocket getWebsocket() {
    return danmuWebsocket;
  }

  public SettingsService getSettingsService() {
    return settingsService;
  }

  public void setEnable(boolean enable) {
    this.enable = enable;
  }

  public boolean isEnable() {
    return enable;
  }

  //

  @SuppressWarnings("unused")
  public static void handle(ByteBuffer message) throws Exception {
    byte[] bytes = ByteUtils.decodeValue(message);
    if (bytes.length <= 0) {
      return;
    }

    BarrageHeader barrageHeader = unpack(bytes);
    int packageLength = barrageHeader.getPackageLength();
    int packageHeaderLength = barrageHeader.getPackageHeadLength();
    int packageVersion = barrageHeader.getPackageVersion();
    int packageType = barrageHeader.getPackageType();
//    int packageOther = barrageHeader.getPackageOther();
    byte[] bs = ByteUtils.subBytes(bytes, packageHeaderLength, packageLength - packageHeaderLength);
    if (packageVersion == 2) {
      if (packageType == 5) {
        handleZlibMessage(ByteUtils.bytesToZlibInflate(bs));
      }
      else {
        String resultStr = HexUtils.toHexString(bs);
        log.debug("！！！！！！！！！！未知数据(1)v:" + packageVersion + "t:" + packageType + ":" + resultStr);
      }
    }
    else if (packageVersion == 1) {
      if (packageType == 3) {
        //房间人气
        GlobalData.ROOM_POPULARITY = ByteUtils.byteslong(bs);
      }
      else if (packageType == 8) {
        // 返回{code 0} 验证头消息成功后返回
        String resultStr = new String(bs, StandardCharsets.UTF_8);
      }
      else {
        String resultStr = HexUtils.toHexString(bs);
        log.debug("！！！！！！！！！！未知数据(1)v:" + packageVersion + "t:" + packageType + ":" + resultStr);
      }
    }
    else if (packageVersion == 0) {
      // 弹幕信息
      String messageString = new String(bs, StandardCharsets.UTF_8);
      MessageHandler.getInstance().handle(messageString);
    }
    else {
      String resultStr = HexUtils.toHexString(bs);
      log.debug("！！！！！！！！！！未知数据(1):" + resultStr);
    }
  }

  /**
   * 处理解压后子数据包
   */
  @SuppressWarnings("unused")
  public static void handleZlibMessage(byte[] bytes) throws Exception {
    int offect = 0;
    String resultStr = null;
    int maxLen = bytes.length;
    int data_len = 0;
    int head_len = 0;
    int data_ver = 0;
    int data_type = 0;
    int data_other = 0;
    byte[] bs = null;
//		int index = 1;
//		LOGGER.debug(maxLen+"长的母数据包打印开始--------------------------------------------------------------------------------");
    while (offect < maxLen) {
      byte[] byte_c  = ByteUtils.subBytes(bytes, offect, maxLen - offect);
      BarrageHeader barrageHeadHandle = unpack(byte_c);
      data_len = barrageHeadHandle.getPackageLength();
      head_len = barrageHeadHandle.getPackageHeadLength();
      data_ver = barrageHeadHandle.getPackageVersion();
      data_type = barrageHeadHandle.getPackageType();
      data_other = barrageHeadHandle.getPackageOther();
//			LOGGER.debug("子包<"+index+">:"+"("+data_len+","+head_len+","+data_ver+","+data_type+","+data_other+")");
      bs = ByteUtils.subBytes(byte_c, head_len, data_len - head_len);
//			resultStr=HexUtils.toHexString(bs);
      if (data_ver == 2) {
        if (data_type == 5) {
          resultStr = ByteUtils.BytesTozlibInflateString(bs);
//					resultStr = ByteUtils.unicodeToString(resultStr);
          log.debug("其他未处理消息(2):" + resultStr);
        }
        else {
          resultStr = HexUtils.toHexString(bs);
          log.debug("！！！！！！！！！！未知数据(2)v:" + data_ver + "t:" + data_type + ":" + resultStr);
        }
      }
      else if (data_ver == 1) {
        if (data_type == 3) {
            GlobalData.ROOM_POPULARITY = ByteUtils.byteslong(bs);
        }
        else {
          resultStr = HexUtils.toHexString(bs);
          log.debug("！！！！！！！！！！未知数据(2)v:" + data_ver + "t:" + data_type + ":" + resultStr);
        }
      }
      else if (data_ver == 0) {
        resultStr = new String(bs, StandardCharsets.UTF_8);
        MessageHandler.getInstance().handle(resultStr);
//				resultStr = ByteUtils.unicodeToString(resultStr);
      }
      else {
        resultStr = HexUtils.toHexString(bs);
        log.debug("！！！！！！！！！！未知数据(2):" + resultStr);
      }
      bs = null;
      offect += data_len;
    }
    resultStr = null;
  }

  public static BarrageHeader unpack(byte[] bytes) {
    BarrageHeader barrageHeader = new BarrageHeader();
    try {
      JavaStruct.unpack(barrageHeader, bytes);
    }
    catch (StructException e) {
      throw new StructRuntimeException(e);
    }
    return barrageHeader;
  }

  /**
   * 弹幕集打包
   * Barrage set packaging
   */
  public static byte[] toBytes(BarrageHeader barrageHeader) {
    try {
      return JavaStruct.pack(barrageHeader);
    }
    catch (StructException e) {
      throw new StructRuntimeException(e);
    }
  }

}
